#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>

int vp_sprint(char* out, const char*fmt,va_list vp);

#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)

static int put_num = 0;
void put_char(char c)
{
	if (c == '\n')
	  put_char('\r');
	putch(c);
  put_num++;
}


void print_num(uint32_t num, int base)
{
	if(num == 0)
	{
		return;
	}
	print_num(num/base, base);
	put_char("0123456789abcdef"[num%base]);							//逆序打印结果
}

void print_str(const char *p)
{
	while (*p)
	put_char(*(p++));
}

void print_hex(uint32_t v, int digits)
{
	for (int i = 7; i >= 0; i--)
	{
		char c = "0123456789abcdef"[(v >> (4*i)) & 15];
		if (c == '0' && i >= digits)
			continue;
		put_char(c);
		digits = i;
	}
}

void print_hex2(uint32_t hex)
{
	if(0 == hex)
	{
		put_char('0');
		return;
	}
	else
	{
		print_num(hex, 16);											//打印十六进制数
	}
}

void print_dec(uint32_t v)
{
	if(0 == v)
	{
		put_char('0');
		return;
	}
	else
	{
		print_num(v, 10);											//打印十进制数
	}
}


int printf(const char *fmt, ...) {
	const char *pfmt = NULL;
	va_list vp;
  put_num = 0;
	va_start(vp, fmt);
	pfmt = fmt;
    int val_int;
	while(*pfmt)
	{
		switch(*pfmt)
		{
			case '%':
			{
				switch(*(pfmt + 1))
				{
					case 'c':
						put_char(va_arg(vp, int));
						pfmt++;
						break;
					case 'd':
					case 'D':
					case 'i':
                        val_int = va_arg(vp, int);
                        if(val_int < 0) {
                            put_char('-');
                            val_int = -val_int;
                        }
						print_dec(val_int);
						pfmt++;
						break;


					case 's':
					case 'S':
						print_str(va_arg(vp, char*));
						pfmt++;
						break;
          case 'p':
          case 'P':
            print_str("0x");
					case 'x':
					case 'X':
						print_hex2(va_arg(vp, int));
						pfmt++;
						break;
					case '%':
						put_char('%');
                        pfmt++;
						break;

					default:
						put_char(*pfmt);
						break;
				}
				break;
			}
			case '\n':
				put_char('\n');
				break;
			case '\t':
				put_char('\t');
				break;
			default:
				put_char(*pfmt);
				break;
		}
		pfmt++;
	}
	va_end(vp);
  return put_num;

}

int vsprintf(char *out, const char *fmt, va_list ap) {
  return -1;
}
static char* sput_char(char*s,char c) {
  *s++ = c;
  return s;
}
static char* sprint_num(char* s,uint32_t num, int base)
{
  if(num == 0)
  {
    return s;
  }
  s = sprint_num(s,num/base, base);
  return sput_char(s,"0123456789abcdef"[num%base]);             //逆序打印结果
}
static char* sprint_str(char* s,const char *p)
{
  while (*p) s = sput_char(s,*(p++));
  return s;
}

static char* sprint_dec(char *s,uint32_t v)
{
  if(0 == v)
  {
    return sput_char(s,'0');
  }
  else
  {
    return sprint_num(s,v, 10);                     //打印十进制数
  }
}

static char* sprint_hex(char *s,uint32_t v)
{
  if(0 == v)
  {
    return sput_char(s,'0');
  }
  else
  {
    return sprint_num(s,v, 16);                     //打印十进制数
  }
}



int vp_sprint(char* out, const char*fmt,va_list vp) {

  char *start_p = out;
  const char *pfmt = fmt;
  int val_int;
  uint32_t val_uint;
  while(*pfmt)
  {
    switch(*pfmt)
    {
      case '%':
      {
        switch(*(pfmt + 1))
        {
          case 'c':
            out = sput_char(out,va_arg(vp, int));
            pfmt++;
            break;
          case 'd':
          case 'D':
          case 'i':
            val_int = va_arg(vp, int); 
            if(val_int < 0) {
                out = sput_char(out,'-');
                val_int = -val_int;
            }
            out = sprint_dec(out,val_int);
            pfmt++;
            break;

          case 'p':
          case 'P':
            out = sprint_str(out,"0x");
          case 'x':
          case 'X':
            val_uint = va_arg(vp, uint32_t); 

            out = sprint_hex(out,val_uint);
            pfmt++;
            break;
          case 's':
          case 'S':
            out = sprint_str(out,va_arg(vp, char*));
            pfmt++;
            break;

          case '%':
            out = sput_char(out,'%');
            pfmt++;
            break;

          default:
            out = sput_char(out,*pfmt);
            break;
        }
        break;
      }
      case '\n':
        out = sput_char(out,'\n');
        break;
      case '\t':
        out = sput_char(out,'\t');
        break;
      default:
        out = sput_char(out,*pfmt);
        break;
    }
    pfmt++;
  }
  *out = '\0';
  return out - start_p;
}

int sprintf(char *out, const char *fmt, ...) {
  // char *pfmt = NULL;
  va_list vp;
  va_start(vp, fmt);
  int ret = vp_sprint(out,fmt,vp);
  va_end(vp);
  return ret;
}

int snprintf(char *out, size_t n, const char *fmt, ...) {
  panic("Not implemented");
}

int vsnprintf(char *out, size_t n, const char *fmt, va_list ap) {
  panic("Not implemented");
}

#endif
